package org.polyforms.repository.strategy.support;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import org.polyforms.repository.executor.NameBasedExecutor;
import org.polyforms.repository.factory.EntityClassResolver;
import org.polyforms.repository.strategy.QueryNamingStrategy;

/**
 * Strategy of resolving query's name with prefix which is name of entity class for specific method.
 * 
 * @author Kuisong Tong
 * @since 1.0
 */
@Named
public final class EntityClassPrefixingQueryNamingStrategy implements QueryNamingStrategy {
    private final EntityClassResolver entityClassResolver;

    /**
     * Create an instance with {@link EntityClassResolver}s.
     */
    @Inject
    public EntityClassPrefixingQueryNamingStrategy(final EntityClassResolver entityClassResolver) {
        this.entityClassResolver = entityClassResolver;
    }

    /**
     * {@inheritDoc}
     */
    public List<String> getQueryName(final Method method, final NameBasedExecutor executor) {
        final List<String> queryNames = new ArrayList<String>();
        final Class<?> entityClass = entityClassResolver.resolve(method.getDeclaringClass());
        if (entityClass != null) {
            final String methodName = method.getName();
            final String prefix = getPrefix(methodName, executor);
            queryNames.add(entityClass.getName() + "." + methodName);
            queryNames.add(entityClass.getSimpleName() + "." + methodName);
            if (prefix != null) {
                queryNames.add(entityClass.getName() + "." + methodName.substring(prefix.length()));
                queryNames.add(entityClass.getSimpleName() + "." + methodName.substring(prefix.length()));
            }
        }
        return queryNames;
    }

    private String getPrefix(final String methodName, final NameBasedExecutor executor) {
        for (final String prefix : executor.getPrefixes()) {
            if (methodName.startsWith(prefix)) {
                return prefix;
            }
        }
        return null;
    }
}
